home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Utilities / MacDOS™ 2.0.0ƒ / User's Guide / B < prev    next >
Encoding:
Text File  |  1994-11-23  |  29.5 KB  |  601 lines  |  [TEXT/ttxt]

  1. B  Extension Programming
  2. Introduction
  3.        With  release  2.0.0, MacDOS™ supports a  new  and  powerful
  4.        piping  mechanism.  This allows programmers  to  extend  the
  5.        functionality   of   MacDOS   through   independent   filter
  6.        applications. The purpose of this section is to explain  how
  7.        the  mechanism works and how programmers can make  the  best
  8.        use of it.
  9.  
  10.        To  provide  more than a simple cookbook, we have structured
  11.        this  section  as  follows: Functional  Specification  (what
  12.        pipes  are  and  what we expect from them); Design  (how  we
  13.        implement  pipes on the Mac); Programmer's Guide  (the  pipe
  14.        toolbox and how to use it).
  15. Functional Specification
  16.        In  an  operating system based on a command  line  interface
  17.        (CLI), each command is usually associated with a process.
  18.  
  19.        A  pipe  is a means of sending information from one  process
  20.        to another. Like water in a physical pipe, information in  a
  21.        software pipe only flows in one direction and what enters  a
  22.        pipe  comes  out of the other end in the same  order  (FIFO:
  23.        First  In First Out). The purpose of such a mechanism is  to
  24.        feed the second process with the output of the first one.
  25.  
  26.        Predictably, another pipe can transfer information from  the
  27.        second  process to a third one, still another pipe from  the
  28.        third  to  the  fourth, etc. The end result is  a  chain  of
  29.        processes in which each process acts as a filter.  Only  the
  30.        two  processes at the beginning and at the end of the  chain
  31.        interact with the user (typically, via the keyboard and  the
  32.        monitor).
  33.  
  34.        In  principle,  each  process  keeps  checking  whether  the
  35.        incoming pipe has something ready to be processed, does  its
  36.        processing  on  the bits and pieces it gets, and  sends  the
  37.        result immediately to the outgoing pipe. In practice, it  is
  38.        the  operating  system that takes care of the  piping.  Each
  39.        process  still  believes that it is getting its  input  from
  40.        the keyboard and sending its output to the monitor.
  41.  
  42.        As  the  processes  are  unaware that they  communicate  via
  43.        pipes,  all input/output is of ASCII characters rather  than
  44.        binary data.
  45.  
  46.        The  Mac  OS is not built around a CLI and does not directly
  47.        support  I/O  redirection  and piping  and  the  concept  of
  48.        standard I/O devices is missing.
  49.  
  50.        Although  MacDOS provides a CLI for the Mac, it operates  at
  51.        the  application level. Therefore, its console window is not
  52.        directly   accessible   to   other   applications.   As    a
  53.        consequence,  Mac applications (unlike UNIX® programs)  must
  54.        be  aware of piping. Furthermore, as the piping mechanism is
  55.        outside the OS, it is bound to be less efficient.
  56.  
  57.        In  view of all these considerations, we can specify  piping
  58.        for the Mac as follows:
  59.        •   Piping   shall   be  capable  of  transferring   several
  60.            characters  in a single operation. This will reduce  the
  61.            overhead due to context switching between processes  and
  62.            to message handling within the processes themselves.
  63.        •   The  last  filter of a chain shall send its output  back
  64.            to  MacDOS,  so that it can be displayed in the  console
  65.            window or redirected to a disk file.
  66.        •   Any  filter  of  a chain shall be able to report  errors
  67.            back  to  MacDOS, so that they can be displayed  in  the
  68.            console window.
  69.        •   The  failure  of any filter of a chain shall  cause  the
  70.            quitting of all other filters and be detected by  MacDOS
  71.            so that it can be reported to the user.
  72.        •   The  user shall be able to terminate the operation of  a
  73.            chain of filters by typing a cntl-C/cmd-dot as with  any
  74.            other MacDOS command.
  75.        •   MacDOS  shall be able to pass to any filter its specific
  76.            switches as typed by the user in the command line.
  77.  
  78.        Additionally:
  79.        •   The  user shall be able to obtain on-line help by typing
  80.            "HELP filterName" at the MacDOS prompt.
  81.        •   MacDOS  and  the filters shall reside on the  same  Mac.
  82.            That  is,  it shall not be possible to start  MacDOS  on
  83.            system  A  and pipe a command to a filter  which  is  on
  84.            system B.
  85.  
  86. Design
  87.        This   section   describes   how  the   generic   functional
  88.        requirements listed above translate into practice. That  is,
  89.        how MacDOS and filters exchange information.
  90.  
  91.    General Strategy
  92.        Under the Mac OS, there are two basic ways for processes  to
  93.        exchange  information: Apple Events  (AEs)  and  Process  to
  94.        Process Communication (PPC).
  95.  
  96.        Communication via AEs is connectionless, in the  sense  that
  97.        each  AE  contains information about its destination process
  98.        (a  bit  like sending letters through the mail). Also,  when
  99.        you  send an AE, you have plenty of options on how you  want
  100.        the  destination process to respond to it. This  provides  a
  101.        lot  of  flexibility but introduces quite a bit of  overhead
  102.        as well.
  103.  
  104.        Communication  via  the PPC toolbox is connection  oriented,
  105.        because  you have to establish a communication session  with
  106.        the  destination process before you can begin to  send  data
  107.        to  it,  but  then you can easily exchange messages  without
  108.        addressing  them (a bit like making a telephone  call).  PPC
  109.        requires  some  additional overhead  at  the  beginning  and
  110.        limits  flexibility  later on, but  it  reduces  the  system
  111.        overhead to do the actual data transfer.
  112.  
  113.        In   view  of  these  considerations,  MacDOS  uses  PPC  to
  114.        implement the pipes.
  115.  
  116.        Before two processes can exchange information via PPC,  they
  117.        have to take the following steps:
  118.        •   Each process opens a communication port (say, process  1
  119.            opens port A and process 2 opens port B).
  120.        •   One  of  the  processes (say, process 1), tells  the  OS
  121.            that it is ready to accept PPC sessions.
  122.        •   The  other  process (in this example, process  2)  tells
  123.            the  OS that it would like to start a session with  port
  124.            A.
  125.  
  126.        Normally, PPC operations are conducted asynchronously.  That
  127.        is,  you  start  an operation by executing a function  which
  128.        returns  immediately. To know when the OS has completed  the
  129.        operation  you  have requested, you have two  possibilities:
  130.        either  you provide the OS with a call-back function  (which
  131.        the  OS  executes upon completion of the operation), or  you
  132.        check a flag.
  133.  
  134.        MacDOS checks the flag, mainly because it is a simpler  (ie.
  135.        safer) mechanism.
  136.  
  137.        As  PPC  sessions  are  bidirectional,  filters  can  easily
  138.        report back to MacDOS local errors and errors detected  when
  139.        communicating with the next filter.
  140.  
  141.    Data Structures
  142.        Each  PPC message contains two fields which can be  used  to
  143.        store information:
  144.        •   A long integer (4 bytes) called "userData".
  145.        •   A buffer called "dataBuffer".
  146.  
  147.        MacDOS uses the four bytes of userData as follows (in  order
  148.        of increasing memory address):
  149.        type   specifies the content of the userData field.
  150.        seqis  a  sequence  number set by MacDOS  to  identify  each
  151.            message.
  152.        srcstands  for  source  and  identifies  the  process  which
  153.            generates the message.
  154.        dststands  for destination and identifies the process  which
  155.            should operate on the message.
  156.  
  157.        dataBuffer  always  contains a  P-string  (ie.  an  unsigned
  158.        character  array with its first byte set to  the  number  of
  159.        characters that form the body of the message).
  160.  
  161.        The possible message types and what they mean are listed  in
  162.        the table at the top of the next page.
  163.  
  164.    Procedures
  165.        A filter needs to:
  166.        •   Initialise  the  piping mechanism (open  the  PPC  port,
  167.            establish  a  session  with the  preceding  filter,  and
  168.            initialise state variables).
  169.        •   Process every incoming message.
  170.        •   Forward   to   the  next  process  every  data   message
  171.            filtered.
  172.        •   Report errors to MacDOS.
  173.        •   Clean  up  (most importantly, close the PPC  port,  that
  174.            otherwise remains open even after the filter has quit).
  175.  
  176.          Type          Corresponding content of dataBuffer
  177.          pipeDataMess  To  be filtered. This is what we use pipes
  178.                        for.
  179.          pipeParmMess  Filter   configuration   parameters   (ie.
  180.                        switches).
  181.          pipeNextMess  MacDOS  uses  this  message  to  direct  a
  182.                        filter to establish a session with the PPC
  183.                        port  of the next filter of the chain.  It
  184.                        consists of the port name followed by  the
  185.                        ID  that  MacDOS has assigned to the  next
  186.                        filter.
  187.          pipeErrMess   The first byte is the Most Significat Byte
  188.                        of  an  error  code  of type  OSType.  The
  189.                        second byte of the dataBuffer is the Least
  190.                        Significant  Byte of the same error  code.
  191.                        When  the  error code is pipeFilteringErr,
  192.                        the  following  bytes of the  message  (if
  193.                        any)  are  characters used by  the  source
  194.                        filter  to send to MacDOS an error message
  195.                        in clear.
  196.  
  197.        MacDOS establishes the chain of filters as follows:
  198.            1  It opens its own PPC port.
  199.            2  It launches the first filter application.
  200.            3  It  establishes  a  PPC session  with  the  resulting
  201.                process  (for this to be possible, each filter  must
  202.                open  a  PPC  port  named like its  own  application
  203.                file).  When establishing the session, the  userData
  204.                field  contains the ID of the filter (typecast  from
  205.                char to long).
  206.            4  It  configures  the filter by sending its  paramaters
  207.                as specified in the command line (pipeParmMess).
  208.            5  It launches the second filter application.
  209.            6  It  directs  the first filter to start a PPC  session
  210.                with  the  resulting new process (via a pipeNextMess
  211.                to the first filter).
  212.            7  It  configures  the second filter via a  pipeParmMess
  213.                like it was done for the first filter.
  214.            8  It  repeats  steps  5 to 7 for all following  filters
  215.                in the chain until the last filter is configured.
  216.            9  It  directs  the last filter to start a  PPC  session
  217.                with MacDOS.
  218.            10 It accepts the session opened by the last filter.
  219.  
  220.        At  this  point, the full chain is completed and the  actual
  221.        processing  of  data  can  begin  (via  messages   of   type
  222.        pipeDataMess).  The  message types  mentioned  so  far  only
  223.        travel  downstream (ie. from left to right in the  chain  of
  224.        filters  as  they appear in the command line),  while  error
  225.        messages  only  travel upstream (ie. back to MacDOS  through
  226.        all intermediate filters in the reverse order).
  227.  
  228.        Each  filter is connected to two sessions. The session  with
  229.        the  preceding  process (upstream) implements  the  incoming
  230.        pipe,   while   the  session  with  the  following   process
  231.        (downstream) implements the outgoing pipe.
  232.  
  233.        A  filter only analyses and acts on messages which  have  as
  234.        destination  the  ID of the filter. All other  messages  are
  235.        forwarded  to  the  other  session unchanged.  This  is  how
  236.        MacDOS  can  build the chain one filter at a  time  and  how
  237.        filters can report errors back to MacDOS.
  238.  
  239.        If  you  are  familiar with concepts of Data  Communication,
  240.        the  PPC  represents a data-link protocol layer  (OSI  level
  241.        2),  while  the way in which MacDOS uses the userData  field
  242.        of  the  messages implements a network protocol  layer  (OSI
  243.        level 3).
  244.  
  245.        As  it  will become clear in the Programmer's Guide section,
  246.        all  configuration and forwarding operations can be "hidden"
  247.        inside a single polling function, so that the programmer  of
  248.        a  new  filter does not need to be concerned with them.  The
  249.        basic structure of a filter is shown in Fig B1.
  250.  
  251.        In most cases, MacDOS generates a data message every time  a
  252.        CR-terminated  line  of  text is completed.  When  a  filter
  253.        receives  a data message, it processes the message,  formats
  254.        the  result of the processing into another pipeDataMess, and
  255.        sends  it to the next filter. When MacDOS receives a message
  256.        from  the last filter, it displays or stores it into a  file
  257.        as requested by the user in the command line.
  258.  
  259.        The   source-destination  pair  of  data   messages   always
  260.        identifies  adjacent processes. That is, data  messages  are
  261.        always processed after crossing a single pipe.
  262.  
  263.        To  avoid  that  MacDOS remains "hanging"  (until  it  times
  264.        out),  filters  must always forward a data  message  to  the
  265.        next  filter.  If, as a result of filtering,  a  filter  has
  266.        nothing  to  forward, it must send a message  with  a  zero-
  267.        length  string in its dataBuffer. On the other hand, nothing
  268.        prevents filters from sending several data messages  to  the
  269.        next  process  as  a  reaction to  a  single  incoming  data
  270.        message.
  271.  
  272.        It  is  particularly important that filters  send  an  empty
  273.        data  message  to  the outgoing pipe when they  receive  one
  274.        from  the incoming pipe. The reason is that MacDOS sends  an
  275.        empty  message  to  flush the filter chain before  prompting
  276.        the user for a new command.
  277.  
  278.        When  a filter is waiting for incoming messages, it normally
  279.        checks  both  the incoming and outgoig pipes.  Nevertheless,
  280.        after  sending  an error message to MacDOS, it  only  checks
  281.        the  incoming  pipe  and quits when it  discovers  that  the
  282.        session has been closed.
  283.  
  284.    The Polling Startegy in Detail
  285.        The  two  PPC  functions  used to  communicate  through  PPC
  286.        sessions   are  PPCRead  and  PPCWrite.  The  filter   shell
  287.        included   in   the  MacDOS  release  uses  both   functions
  288.        asynchronously.  DO  NOT  MODIFY ANY  VARIABLE  USED  IN  AN
  289.        ASYNCHRONOUS  PPC-CALL  BEFORE THE OPERATION  IS  COMPLETED.
  290.        If  you  do, you will cause unpredictable system errors  and
  291.        will have to restart your Mac.
  292.  
  293.        A  filter keeps an outstanding asynchronous PPCRead for each
  294.        started  session. This means that as soon as it  receives  a
  295.        message  from  a pipe, it saves the message and  immediately
  296.        initiates a new Read operation.
  297.  
  298.        When  checking  whether a new message has arrived  (see  the
  299.        PipePollOnce  function described in  the  next  section),  a
  300.        filter  always  checks the outgoing pipe first.  This  gives
  301.        priority  to  error  messages (which travel  upstream).  The
  302.        filter  then  keeps  checking each pipe  in  a  round  robin
  303.        fashion.   After  checking  a  pipe,  the  filter   executes
  304.        WaitNextEvent  so  that  the  Mac  OS  can  activate   other
  305.        processes.
  306.  
  307.        To  send  a message to a pipe (data messages to the outgoing
  308.        pipe  or  error  messages  to the incoming  pipe)  a  filter
  309.        executes  an asynchronous PPCWrite. It then only checks  for
  310.        the  completion  of  the PPCWrite before  sending  the  next
  311.        message to the same pipe.
  312.  
  313.        Typically,  a  filter spends most of its  time  polling  the
  314.        pipes and processing data messages. As explained above,  the
  315.        pipe  polling generates a lot of calls to WaitNextEvent.  If
  316.        you  type  a  cntl-C (or a cmd-dot), Wait NextEvent  returns
  317.        successfully and the filter sends to MacDOS the  error  code
  318.        userCanceled. In fact, keyboard events are the  only  events
  319.        that a filter handles.
  320.  
  321.    Handling of the Sequence Number
  322.        MacDOS  uses the seq field of the userData to decide whether
  323.        it  can  send  a new message and whether it can  prompt  the
  324.        user  for  the next command. To achieve this result,  MacDOS
  325.        stamps  all outgoing messages with ever increasing  sequence
  326.        numbers.  As  sequence numbers are stored in  8  bits,  they
  327.        wrap  around  256  (ie. they restart from 0  after  reaching
  328.        255).
  329.  
  330.        The  Mac OS ensures that messages are delivered in the  same
  331.        order  in  which  they  are  sent,  but  MacDOS  checks  the
  332.        sequence  of  incoming messages and aborts the command  when
  333.        it  receives  a  message with a sequence number  lower  than
  334.        that  of  the previous message. This is a safety  precaution
  335.        to  protect  MacDOS against some effects of  badly  designed
  336.        filter  applications  (they could corrupt  the  userData  of
  337.        messages).
  338.  
  339.        When  sending a data message to the outgoing pipe, a  filter
  340.        uses  the sequence number of the last message received  from
  341.        the  incoming  pipe. Therefore, if a filter  responds  to  a
  342.        single  incoming message by sending several messages to  the
  343.        next  filter,  all  those messages have  the  same  sequence
  344.        number.
  345.  
  346.        Before  sending  a data message, MacDOS always  updates  the
  347.        sequence  number.  Then, after sending the  message,  MacDOS
  348.        expects to receive from the incoming pipe the filtered  data
  349.        message  with the same sequence number. Only after receiving
  350.        such  a message, can MacDOS resume execution of the original
  351.        command   (this   is   why  filters  must   always   forward
  352.        something).
  353.  
  354.        Now,  when  a  filter sends several messages with  the  same
  355.        sequence number, MacDOS does not realise it until it  begins
  356.        waiting  for  the reply to its next message. In  that  case,
  357.        MacDOS  keeps processing all the incoming messages until  it
  358.        receives  a  message with the expected sequence  number.  In
  359.        this  way,  unless a filter "misbehaves", MacDOS avoids  the
  360.        piling up of incoming messages.
  361.  
  362.        After  completing execution of the original command,  MacDOS
  363.        sends  a  data  message  with  an  empty  dataBuffer.   This
  364.        effectively  "flushes" the chain of pipes and  ensures  that
  365.        no  filter-generated  messages are outstanding.  Only  after
  366.        receiving the corresponding empty message from the  incoming
  367.        pipe,  does MacDOS close the PPC port and prompts  the  user
  368.        for a new command.
  369.  
  370.    Data Flow
  371.        This  section  illustrates in a graphic  form  how  messages
  372.        travel  through  the chain of filters. For this  purpose,  a
  373.        chain   of  two  filters  is  used.  In  all  the  following
  374.        diagrams, messages travelling downstream are represented  by
  375.        arrows pointing to the right.
  376.  
  377.        Fig B2 shows how MacDOS sets the chain up.
  378.  
  379.        The  dashed  lines correspond to interactions with  the  PPC
  380.        other than for sending messages. Each number IDentifies  the
  381.        destination  filter,  both  for  messages  and   for   other
  382.        actions.
  383.  
  384.        Note  that  each filter performs a PipeInit (which  includes
  385.        accepting  incoming PPC session requests) immediately  after
  386.        launch,  while MacDOS only accepts sessions after  directing
  387.        the last filter to start one.
  388.  
  389.        Once  the initialisation is completed, both filters  are  in
  390.        their default state, waiting for data messages.
  391.  
  392.        Fig  B3 shows how the normal data transfer looks in a simple
  393.        case.
  394.  
  395.        After   sending  a  data  message,  MacDOS  waits  for   the
  396.        corresponding  data  message from its  incoming  pipe.  Note
  397.        that   both  filters  are  in  their  default  state  before
  398.        receiving   the  data  message  and  after  completing   its
  399.        processing:  they  poll the pipes waiting for  something  to
  400.        do.
  401.  
  402.        Fig  B4  provides  an example of data transfer  in  which  a
  403.        filter sends two messages for each message it receives.
  404.  
  405.        Note how MacDOS polls again after displaying 1b. It does  so
  406.        because  MacDOS  has  already sent a message  with  sequence
  407.        number 2, while 1b has still sequence number 1. MacDOS  will
  408.        only  see  2b  while waiting for 3, etc. After  sending  the
  409.        last line with, say, sequence number N, MacDOS will send  an
  410.        empty  message with sequence number N + 1, so as  to  detect
  411.        possible Nb, Nc, etc.
  412.  
  413.        Fig  B5  shows  how  filters report error messages  back  to
  414.        MacDOS.
  415.  
  416.        The  filters  quit  when they find out that  their  incoming
  417.        pipe  has disappeared (ie. that the incoming session  is  no
  418.        longer  there).  Therefore, as soon  as  MacDOS  closes  its
  419.        session  with  the  first filter, that  filter  quits.  This
  420.        causes  the  disappearence  of  the  next  pipe,  etc.  This
  421.        cascading effect terminates when the last filter quits.
  422.  
  423. Programmer's Guide
  424.        This  section  describes  the  functions  provided  in   the
  425.        "filter  shell" project. It also tells you how to  structure
  426.        and build a filter application.
  427.  
  428.    Pipe Toolbox
  429.        The  pipe.c/pipe.h  sources provide the following  functions
  430.        (in alphabetical order):
  431.  
  432.        void PipeInit(pipeParmsFun_t *parmsFun);
  433.  
  434.            PipeInit  prepares  the filter to handle pipe  messages.
  435.                It  opens  the  PPC  port  and  only  returns  after
  436.                establishing a session with the process upstream.
  437.            
  438.            parmsFun  is  a  pointer  to  a function  which  accepts
  439.                configuration  parameters  as  they  appear  in  the
  440.                command  line and saves them in variables accessible
  441.                during  filtering. Set it to nil if your  filter  is
  442.                not configurable.
  443.  
  444.        void PipePoll(unsigned char *inMess);
  445.  
  446.            PipePoll waits for messages from either PPC session.  It
  447.                automatically handles all messages unless  they  are
  448.                data  messages received from the incoming  pipe  and
  449.                directed to the filter itself.
  450.            
  451.            inMess  is the pointer to the buffer where PipePoll  can
  452.                store  an  incoming  message. inMess  should  be  at
  453.                least  pipeSize  byte long and  will  contain  a  P-
  454.                string when PipePoll returns successfully.
  455.  
  456.        void PipeReportError(
  457.                             OSErr        err,
  458.                             unsigned char  *errInClear
  459.                             );
  460.  
  461.            PipeReportError  sends an error message  to  MacDOS.  It
  462.                can  be  used  to  report errors encountered  during
  463.                filtering.
  464.            
  465.            err is  the  error  code.  To  have  MacDOS  display   a
  466.                proprietary    error    string,    set    err     to
  467.                pipeFilteringErr.   MacDOS   will    then    display
  468.                errInClear.
  469.            
  470.            errInClear is a proprietary error string that you  would
  471.                like  MacDOS  to  display  in  the  console  window.
  472.                MacDOS  only looks at this string if you set err  to
  473.                pipeFilteringErr.  If  you  use  PipeReportError  to
  474.                report  a Mac system error rather than a proprietary
  475.                error, you can set errInClear to nil.
  476.  
  477.        void PipeSendData(unsigned char *outMess);
  478.  
  479.            PipeSendData   sends  a  message  to  the  next   filter
  480.                downstream.
  481.            
  482.            outMess  is  the  pointer to the buffer  containing  the
  483.                message  to be sent. outMess must contain a P-string
  484.                and cannot occupy more than pipeSize bytes.
  485.  
  486.        Note  that  the  Pipe  functions only  return  if  they  are
  487.        successful. Otherwise, they automatically attempt to  report
  488.        to  MacDOS  the first error they encounter. They  then  wait
  489.        for MacDOS to "cut" the pipes.
  490.  
  491.        NEVER  "DROP  OFF  THE  BOTTOM" OF A FILTER.  Let  the  Pipe
  492.        functions  take  care  of quitting the  filter  application.
  493.        This  will ensure that the filter closes its PPC port before
  494.        quitting.  If  the PPC port remains open, you  will  not  be
  495.        able  to re-use the same filter unless you restart your  Mac
  496.        (or  change  the  filter  application  name,  although  this
  497.        technique  would lead to a proliferation of  "ghost"  ports.
  498.        Only do it in emergency).
  499.  
  500.    Filter Structure
  501.        The  "filter  shell"  hides most of the  complexities  of  a
  502.        filter   to   the   programmer.  The  resulting   simplified
  503.        structure of a typical filter is shown in Fig B6.
  504.  
  505.    Debugging Filter Projects
  506.        In  order to debug filters, you have to know how to  do  two
  507.        things:
  508.        1  Launch  your filter project instead of a compiled  filter
  509.            application.
  510.        2  Have  MacDOS  wait  for you when you pause  execution  of
  511.            the filter project with a breakpoint.
  512.  
  513.        The  first  issue  exists because MacDOS rightly  recognises
  514.        that  your  filter project is not a filter  application.  It
  515.        expects  a  file of type 'APPL' and creator  'mFLR'  but  it
  516.        finds a file of type 'PROJ' and creator 'KAHL' (only if  you
  517.        are  using  THINK  C, but the discussion remains  valid  for
  518.        other compilers). To trick MacDOS, do as follows:
  519.        •   Place  an  alias of the file fakeFilter.π in the  folder
  520.            where you keep MacDOS.
  521.        •   Rename the alias like your filter project.
  522.        •   Run  your filter project, set the breakpoint[s], and let
  523.            it go.
  524.        •   Click  in  the MacDOS console window to push the  filter
  525.            process  to  the  background and  bring  MacDOS  to  the
  526.            front.
  527.        •   Type  the  command  that you want to use  to  test  your
  528.            filter,  but only type the name of your filter  project,
  529.            without  its  real  path. MacDOS will  see  the  renamed
  530.            fakeFilter  and will happily launch it (it will  die  at
  531.            once).  MacDOS  will  then  succeed  in  opening  a  PPC
  532.            session  with the filter port, because your project  was
  533.            already   running  and  had  already  opened  the   port
  534.            correctly.
  535.  
  536.        This  trick  works because the name of a filter  application
  537.        coincides  with  the  name of the PPC  port  opened  by  the
  538.        filter.
  539.  
  540.        The  second  issue  exists because MacDOS normally  waits  a
  541.        couple  of  seconds  for data messages  to  be  looped  back
  542.        through  the  filter chain. If you pause  execution  of  the
  543.        filter with a breakpoint, MacDOS will timeout and abort  the
  544.        command.  The  solution is simple because  MacDOS  sets  the
  545.        timeout  to  the number of seconds specified in  the  global
  546.        variable     TIMEOUT.     Therefore,     if     you     type
  547.        "set timeout=3600"  at the prompt, MacDOS will wait for  one
  548.        hour before timing out.
  549.  
  550.    Building a Filter Application
  551.        The  simplest  way  to build a filter is  to  duplicate  and
  552.        rename  the  files filter.c, filter.π, and  filter.π.rsrc  .
  553.        Within filter.c, you only need to modify the content of  the
  554.        function  doFiltering (and HandleParameters if you  want  to
  555.        use switches in the command line).
  556.  
  557.        The  file type of filters is 'APPL' (no 'APPE', please), and
  558.        their   creator  is  'mFLR'.  The  fact  that   all   filter
  559.        applications  have  the same creator  should  not  pose  any
  560.        problem,  because  MacDOS looks for them  by  name,  and  no
  561.        document   file  type  is  defined  for  the  same  creator.
  562.        Therefore,  as  you will not be able to start  a  filter  by
  563.        double  clicking  on a document, the Mac OS  will  never  be
  564.        placed  in  the  position  of  having  to  choose  a  filter
  565.        application on the basis of its creator string.
  566.  
  567.        The  project  filters.π gives you some examples  of  how  to
  568.        define  filter parameters and forward multiple  messages  to
  569.        MacDOS.
  570.  
  571.        The  HELP  command of MacDOS now supports  on-line  help  of
  572.        filter applications. What you need to do in order to set  up
  573.        an  help message for your filter is to include a resource of
  574.        type  'TEXT'  named "help" in its resource  fork  (the  name
  575.        "help"  is  not  case sensitive). If you open  filter.π.rsrc
  576.        with  resEdit,  you  will see that it already  contains  the
  577.        default  help  message: Sorry, no help  available  for  this
  578.        filter.
  579.  
  580. Abbreviations
  581. AE    Apple Events
  582. ASCII American  Standard  Code of Information Interchange.  This is
  583.       the  encoding  of  characters chosen by IBM, Apple,  and most
  584.       other computer manufacturers. The standard encoding assigns a
  585.       value  between 0 and 127 to 128 characters. Apple defines 128
  586.       additional  characters to cover all 256 possible combinations
  587.       of 8 bits.
  588. CLI   Command Line Interface.
  589. CR    The  ASCII character Carriage Return. This is how the  Mac OS
  590.       separates lines of text.
  591. DOS   Disk OS (most common Operating System for PCs).
  592. FIFO  First In First Out
  593. IBM   Industrial  Business  Machines (although  they  have recently
  594.       changed the meaning of 'IBM')
  595. ISO   International Organisation for Standardisation
  596. OS    Operating System
  597. OSI   Open   System   Interconnection.  ISO's  layered   model  for
  598.       communication protocols.
  599. PPC   Process to Process Communication toolbox
  600. RH    Rainbow Hill Pty Ltd.
  601.